///\todo upgrade

//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2012 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _BUOLA_IMAGE_RASTERIZER_CSCANLINES_H_
#define _BUOLA_IMAGE_RASTERIZER_CSCANLINES_H_

#include <buola/image.h>

namespace buola { namespace img {

class CScanlines
{
public:
    struct SSpan
    {
        int mX;
        int mLen;
        uint8_t mCover;
    };
    
    struct SLine
    {
        int mFirst;
        int mLast;
    };
    
    CScanlines()=default;
    CScanlines(const CScanlines&)=delete;

    void Reset(int pMinY,int pMaxY)
    {
        mMinY=pMinY;
        mLines.resize(pMaxY-pMinY+1);
        mSpans.clear();
    }
    
    void StartLine(int pY)
    {
        mLines[pY-mMinY].mFirst=mSpans.size();
    }
    
    void EndLine(int pY)
    {
        mLines[pY-mMinY].mLast=mSpans.size();
    }
    
    void AddSpan(int pX,int pLen,uint8_t pCover)
    {
        SSpan lSpan={pX,pLen,pCover};
        mSpans.push_back(lSpan);
    }
    
    void Print()
    {
        msg_info() << "scanlines: " << mSpans.size() << " " << mLines.size() << "\n";
    }
    
    int First(int pY)   {   return mLines[pY-mMinY].mFirst; }
    int Last(int pY)    {   return mLines[pY-mMinY].mLast; }
    const SSpan& Span(int i)    {   return mSpans[i];       }
    
    int MinY()          {   return mMinY;   }
    int MaxY()          {   return mMinY+mLines.size()-1;   }

private:
    int mMinY;
    std::vector<SSpan> mSpans;
    std::vector<SLine> mLines;
};

template<typename tRenderer>
class CIntersectionRenderer
{
public:
    CIntersectionRenderer(tRenderer &pRenderer,CScanlines &pSL)
        :   mRenderer(pRenderer)
        ,   mSL(pSL)
    {}
    
    void RenderSpans(int pY,int *pXs,int *pLens,uint8_t *pCovers,int pN)
    {
        if(pY<mSL.MinY()||pY>mSL.MaxY()) return;
        
        int lFirst=mSL.First(pY);
        int lLast=mSL.Last(pY);
        
        int i=0;
        while(i<pN&&lFirst<lLast)
        {
            const CScanlines::SSpan &lSpan=mSL.Span(lFirst);
            int xb1 = lSpan.mX;
            int xb2 = pXs[i];
            int xe1 = xb1+lSpan.mLen-1;
            int xe2 = xb2+pLens[i]-1;

            // Determine what spans we should advance in the next step
            // The span with the least ending X should be advanced
            // advance_both is just an optimization when we ending 
            // coordinates are the same and we can advance both
            //--------------
            bool advance_span1 = xe1 <  xe2;
            bool advance_both  = xe1 == xe2;

            // Find the intersection of the spans
            // and check if they intersect
            //--------------
            if(xb1 < xb2) xb1 = xb2;
            if(xe1 > xe2) xe1 = xe2;
            if(xb1 <= xe1)
            {
                int lCover=lSpan.mCover*(pCovers[i]+1);
                mRenderer.RenderHLine(xb1,pY,xe1-xb1+1,lCover>>8);
            }

            // Advance the spans
            //--------------
            if(advance_both)
            {
                i++;
                lFirst++;
            }
            else
            {
                if(advance_span1)
                {
                    lFirst++;
                }
                else
                {
                    i++;
                }
            }
        }
    }
    
private:
    tRenderer &mRenderer;
    CScanlines &mSL;
};

/*namespace image*/ } /*namespace buola*/ }

#endif
